package com.fsbm.ctech.maxis.ebpsbackend;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.security.Key;
import java.security.KeyPair;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.Security;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMDecryptorProvider;
import org.bouncycastle.openssl.PEMEncryptedKeyPair;
import org.bouncycastle.openssl.PEMKeyPair;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
import org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder;

public class CryptoUtil {

	public static void main(String[] args) throws Exception {
		// MaxisBillPem rsaObj = new MaxisBillPem();
		String path = "D:\\workspaceE\\Backend\\";
		String PRIVATE_KEY_FILE = path + "private.pem";
		String PUBLIC_KEY_FILE = path + "encfile.dat";
		
		KeyPair privateKeyPair = readKeyPair(new File(PRIVATE_KEY_FILE),"maxis123");

		Key privateKey = privateKeyPair.getPrivate();

		byte[] aeskey = RSADecrypt(privateKey, PUBLIC_KEY_FILE);
		
		String url = "https://202.179.127.245/itmd-sit/sb?p=";
//		String param = "1700249400|601112832757|4|141120";
		String param = URLDecoder.decode("8Dauh9EUzS1rLfcjZEbBOMtfYi7tt4L%2FfW19VLRCR0w%3D", "UTF-8");
		
		String encParam = null;
		//byte[] encData = AESEncrypt(aeskey, param);
		byte[] data = AESDecrypt(aeskey, Base64.decodeBase64(param.getBytes()));
		System.out.println(new String(data));
//		byte[] base64Encoded = null;
//		if (encData != null) {
//			base64Encoded = Base64.encodeBase64(encData);
////			System.out.println("Base64Encoded Param: " + new String(base64Encoded));
//		}
//		if(base64Encoded != null) {
//			encParam = URLEncoder.encode(new String(base64Encoded),"UTF-8");
//		}
//		encParam = URLEncoder.encode(new String(encData),"UTF-8");
		
//		System.out.println("Before Encryption URL: " + url + param);
//		System.out.println("After Encryption URL: " + url + encParam);
//		AESDecrypt(aeskey, Base64.decodeBase64(base64Encoded));
	}

	public static KeyPair readKeyPair(File privateKey, String keyPassword)
			throws IOException {
		FileReader fileReader = null;
		try {
			fileReader = new FileReader(privateKey);
			PEMParser pemParser = new PEMParser(fileReader);
			Object object = pemParser.readObject();
			PEMDecryptorProvider decProv = new JcePEMDecryptorProviderBuilder()
					.build(keyPassword.toCharArray());
			JcaPEMKeyConverter converter = new JcaPEMKeyConverter();
			KeyPair kp;
			if (object instanceof PEMEncryptedKeyPair) {
//				System.out.println("Encrypted key - we will use provided password");
				kp = converter.getKeyPair(((PEMEncryptedKeyPair) object)
						.decryptKeyPair(decProv));
			} else {
//				System.out.println("Unencrypted key - no password needed");
				kp = converter.getKeyPair((PEMKeyPair) object);
			}

			return kp;
		} catch (IOException ex) {
			throw ex;
		} finally {
			if (fileReader != null) {
				fileReader.close();
			}
		}
	}

	private static Key readKey(File keyFile, String password)
			throws IOException {
		FileReader fileReader = null;
		try {
			fileReader = new FileReader(keyFile);
			PEMParser pemParser = new PEMParser(fileReader);
			Object object = pemParser.readObject();
			// PEMDecryptorProvider decProv = new
			// JcePEMDecryptorProviderBuilder().build(password.toCharArray());
			JcaPEMKeyConverter converter = new JcaPEMKeyConverter();
			Key key = null;
			if (object instanceof PrivateKeyInfo) {
				key = converter.getPrivateKey((PrivateKeyInfo) object);
			} else if (object instanceof SubjectPublicKeyInfo) {
				key = converter.getPublicKey((SubjectPublicKeyInfo) object);
			}
			return key;
		} catch (IOException ex) {
			throw ex;
		} finally {
			if (fileReader != null) {
				fileReader.close();
			}
		}
	}

	private static byte[] RSAEncrypt(Key pubkey, String text) {
		try {
			Cipher rsa;
			rsa = Cipher.getInstance("RSA/None/PKCS1Padding");
			rsa.init(Cipher.ENCRYPT_MODE, pubkey);
			return rsa.doFinal(text.getBytes());
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	private static byte[] RSADecrypt(Key decryptionKey, byte[] buffer) {
		try {
			Cipher rsa;
			Security.addProvider(new BouncyCastleProvider());
			rsa = Cipher.getInstance("RSA/None/PKCS1Padding","BC");
			rsa.init(Cipher.DECRYPT_MODE, decryptionKey);
			byte[] decData = rsa.doFinal(buffer);
			return decData;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	
	public static byte[] RSADecrypt(Key privateKey, String inFileName) throws Exception {
		try {
//			System.out.println("Encrypted file: " + inFileName);
			FileInputStream cipherfile = new FileInputStream(inFileName);
			byte[] ciphertext = new byte[cipherfile.available()];
			cipherfile.read(ciphertext);
			cipherfile.close();
			return RSADecrypt(privateKey, ciphertext);
			
		} catch (Exception e) {
			e.printStackTrace();
			throw new Exception("Could not decrypt the data. " + e.getMessage());
		}
	}

	public static byte[] AESEncrypt(byte[] key, String value) {
		byte[] encData = null;
		try {
//			System.out.println("AESEncypting " + value);
			byte[] dataToSend = value.getBytes("UTF-8");
			Cipher c = Cipher.getInstance("AES");
			c.init(Cipher.ENCRYPT_MODE, buildKey(key)); 
			
	        encData = c.doFinal(dataToSend);
	        
//	        System.out.println("AESEncrypted Data: " + new String(encData, "UTF-8"));
		} catch (Exception ex) {
			ex.printStackTrace();
		}
		return encData;
	}
	
	public static byte[] AESEnccrypt(String privateKeyFile, String privateKeyPass, String secretKeyFile, String data) throws Exception{
		byte[] encData = null;
		try {
			KeyPair privateKeyPair = readKeyPair(new File(privateKeyFile), privateKeyPass);

			Key privateKey = privateKeyPair.getPrivate();

			byte[] aeskey = RSADecrypt(privateKey, secretKeyFile);
			encData = AESEncrypt(aeskey, data);

		} catch (Exception e) {
			e.printStackTrace();
			throw new Exception("Could not encrypt the parameters. " + e.getMessage());
		}
		return encData;
	}
	
	public static byte[] AESDecrypt(byte[] key, byte[] cipher) throws Exception {
		try {
//			System.out.println("AESDecrypting cipher: " + new String(cipher, "UTF-8"));
			Cipher c = Cipher.getInstance("AES");
			c.init(Cipher.DECRYPT_MODE, buildKey(key));
			byte[] data = c.doFinal(cipher);
			return data;
//			System.out.println("AESDecrypted data: " + new String(data));
		} catch (Exception ex) {
			ex.printStackTrace();
			throw new Exception("Could not decrypt the cipher. " + ex.getMessage());
		}
	}
	
	private static Key buildKey(byte[] key) throws NoSuchAlgorithmException, UnsupportedEncodingException {
		//System.out.println("Symmetric key: " + new String(key, "UTF-8"));
	    MessageDigest digester = MessageDigest.getInstance("SHA-256");
	    byte[] hashedKey = digester.digest(key);
	    //System.out.println("Symmetric hashed key: " + new String(hashedKey, "UTF-8") + "|" + bytesToHex(hashedKey));
	    SecretKeySpec spec = new SecretKeySpec(hashedKey, "AES");
	    return spec;
	}
	
	public static String bytesToHex(byte[] bytes) {
        StringBuffer result = new StringBuffer();
        for (int i = 0; i < bytes.length; i++) {
        	result.append(Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1));
		}
        return result.toString();
    }
}
